import 'dart:async';
import 'dart:math';

import 'package:auto_route/auto_route.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:sonora/bloc/base/sj_base_bloc.dart';
import 'package:sonora/bloc/home/sj_home_event.dart';
import 'package:sonora/bloc/home/sj_home_state.dart';
import 'package:sonora/models/sj_broad_caster_data.dart';
import 'package:sonora/models/sj_config_data.dart';
import 'package:sonora/models/sj_friend_list_item_data.dart';
import 'package:sonora/models/sj_response_data.dart';
import 'package:sonora/models/sj_works_model.dart';
import 'package:sonora/repository/sj_home_repository.dart';
import 'package:sonora/utils/sj_storage_utils.dart';
import 'package:sonora/utils/sj_utils.dart';
import 'package:sonora/views/navigation/routes/sj_app_router.dart';

import '../../models/sj_login_response_data.dart';

class SjHomeBloc extends SjBaseBloc<SjHomeEvent, SjHomeState> {
  final SjHomeRepository repository;

  SjHomeBloc(this.repository) : super(const SjHomeState()) {
    on<SjHomeEventInitial>(_onInitial);
    on<SjHomeEventClickLikeButton>(_onClickLikeButton);
    on<SjHomeEventNetworkError>(_onNetworkError);
    on<SjHomeEventLoadedWallSearch>(_onLoadedWallSearch);
    on<SjHomeEventInsertRecord>(_onAddBlock);
    on<SjHomeEventLoadedFollowList>(_onLoadFollowList);
    on<SjHomeEventLoadedBlockList>(_onLoadBlockList);
    on<SjHomeEventUnFriend>(_onUnFriend);
    on<SjHomeEventFriend>(_onAddFriend);
    on<SjHomeEventInsertReport>(_onAddReport);
  }

  FutureOr<void> _onInitial(
      SjHomeEventInitial event, Emitter<SjHomeState> emit) async {
    try {
      emit(state.copyWith(loading: true));

      SjResponseData responseData = await repository.validToken();
      if (responseData.data is bool && responseData.data == false) {
        // token 失效 跳转到登录页
        emit(state.copyWith(loading: false));
        SjStorageUtils.clearLoginInfo();
        event.context.router.replace(const SjLoginRoute());
        return;
      }

      // 策略
      SjResponseData strategy = await repository.getStrategy();
      if (strategy.success is bool && strategy.success == true) {
        await SjStorageUtils.saveStrategyData(strategy.data);
      }

      // config
      SjConfigData? configData = await repository.getAppConfig();
      if (configData != null) {
        await SjStorageUtils.saveAppConfig(configData);
      }
      // SjStorageUtils.clearWorksList();
      List<SjBroadCasterData>? wallList =
          await SjStorageUtils.getWallSearchList();
      if (wallList == null || wallList.isEmpty) {
        wallList = await repository.getWallSearch();
        wallList = await repository.getWallSearch();
        await SjStorageUtils.saveWallSearch(wallList);
      }
      final randomWallList = SjUtils.getRandomElements(wallList, 6);
      List<SjWorksModel>? works = await SjStorageUtils.getWorksList();
      if (works == null || works.isEmpty) {
        works = SjUtils.mockWorksMatchCaster(wallList);
        SjStorageUtils.saveWorksList(works);
      }
      works ??= [];
      final list = await repository.blockList();
      List<SjWorksModel> result = List.from([]);
      bool match = false;
      for (var element in works) {
        match = false;
        for (var block in list) {
          if (element.userId == block.broadcasterId) {
            match = true;
            break;
          }
        }
        if (!match) {
          result.add(element);
        }
      }

      emit(state.copyWith(
          wallList: wallList,
          randomWallList: randomWallList,
          loading: false,
          worksList: result));
      SjResponseData userResponseData = await repository.getUserInfo();
      if (userResponseData.success != null &&
          userResponseData.success == true) {
        SjStorageUtils.saveUserDetail(userResponseData.data);
      }
    } catch (e) {
      emit(state.copyWith(loading: false));
    }
  }

  FutureOr<void> _onClickLikeButton(
      SjHomeEventClickLikeButton event, Emitter<SjHomeState> emit) async {
    List<SjWorksModel>? updateWorksList =
        List<SjWorksModel>.from(state.worksList ?? []);
    if (updateWorksList.isNotEmpty) {
      SjWorksModel w = updateWorksList
          .firstWhere((element) => element.worksId == event.worksId);
      int index = updateWorksList.indexOf(w);
      w = w.copyWith(isLiked: !event.isLiked);
      int followed = 0;
      int liked = 0;
      if (event.isLiked) {
        if (w.followed != null && w.followed! > 0) {
          followed = w.followed! - 1;
        }

        if (w.liked != null && w.liked! > 0) {
          liked = w.liked! - 1;
        }
      } else {
        if (w.followed == null) {
          followed = 1;
        } else {
          followed = w.followed! + 1;
        }

        if (w.liked == null) {
          liked = 1;
        } else {
          liked = w.liked! + 1;
        }
      }
      w = w.copyWith(followed: followed, liked: liked);
      updateWorksList[index] = w;
      emit(state.copyWith(worksList: updateWorksList));
      SjStorageUtils.updateWorksList(updateWorksList);
    }
  }

  FutureOr<void> _onNetworkError(
      SjHomeEventNetworkError event, Emitter<SjHomeState> emit) {
    emit(state.copyWith(loading: !state.loading));
  }

  Future<void> postArticle(
      String title, String description, List<String> postImageList) async {
    try {
      EasyLoading.show();
      await Future.delayed(const Duration(seconds: 2));

      SjLoginData? loginData = await SjStorageUtils.getLoginInfo();
      SjWorksModel articleModel = SjWorksModel(
        worksId: SjUtils.generateTimeBasedId(),
        title: title,
        des: description,
        userId: loginData!.userInfo!.userId!,
        author: loginData!.userInfo!.userId!,
        avatar: loginData.userInfo!.avatarThumbUrl!,
        nickname: loginData.userInfo?.nickname,
        followed: 0,
        cover: postImageList.elementAt(0),
        works: postImageList,
        comments: [],
        // type: WSArticleModel.typePreformance,
      );
      await SjStorageUtils.insertWork(articleModel);
      List<SjWorksModel> list = List.from(state.worksList ?? []);
      list.insert(0, articleModel);
      emit(state.copyWith(worksList: list));
    } catch (e, s) {
    } finally {
      EasyLoading.dismiss();
    }
  }

  Future<void> addComment(
      SjWorksModel data, SjWorksCommentModel comment) async {
    print('----------------------data.worksId ${data.worksId}');
    print('----------------------comment $comment');

    List<SjWorksCommentModel> comments = List.from(data.comments ?? []);
    comments.insert(0, comment);
    List<SjWorksModel> list = List.from(state.worksList!);
    int index = -1;
    for (int i = 0; i < list.length; i++) {
      if (list[i].worksId == data.worksId) {
        index = i;
        break;
      }
    }
    if (index != -1) {
      SjWorksModel model = list[index].copyWith(comments: comments);
      print('----------------------${model.comments}');
      list[index] = model;
      emit(state.copyWith(worksList: list));
      SjStorageUtils.updateWorksList(list);
    }
  }

  void changeLike(SjWorksModel data, bool flag) {
    List<SjWorksModel> list = List.from(state.worksList!);
    int index = -1;
    for (int i = 0; i < list.length; i++) {
      if (list[i].worksId == data.worksId) {
        index = i;
        break;
      }
    }
    if (index != -1) {
      SjWorksModel model = list[index].copyWith(isLiked: flag);
      list[index] = model;
      emit(state.copyWith(worksList: list));
      SjStorageUtils.updateWorksList(list);
    }
  }

  FutureOr<void> _onLoadedWallSearch(
      SjHomeEventLoadedWallSearch event, Emitter<SjHomeState> emit) async {
    // 延时 3 秒
    await Future.delayed(const Duration(seconds: 2));

    List<SjBroadCasterData>? wallList =
        await SjStorageUtils.getWallSearchList();
    if (wallList == null || wallList.isEmpty) {
      wallList = await repository.getWallSearch();
      await SjStorageUtils.saveWallSearch(wallList);
    }
    List<SjWorksModel>? works = await SjStorageUtils.getWorksList();
    if (works == null || works.isEmpty) {
      works = SjUtils.mockWorksMatchCaster(wallList);
    }
    if (works != null) {
      works.shuffle(Random());
      SjStorageUtils.saveWorksList(works);
    }
    event.callback?.call();
    emit(state.copyWith(loading: false, worksList: works));
  }

  FutureOr<void> _onAddFriend(
      SjHomeEventFriend event, Emitter<SjHomeState> emit) async {
    SjResponseData response = await repository.addFriend(event.followUserId);
    if (response.success != null && response.success == true) {
      add(const SjHomeEventLoadedFollowList());
      EasyLoading.showSuccess('Followed successfully',
          duration: const Duration(seconds: 2));
    }
  }

  FutureOr<void> _onUnFriend(
      SjHomeEventUnFriend event, Emitter<SjHomeState> emit) async {
    try {
      SjResponseData response = await repository.unFriend(event.followUserId);
      if (response.success != null && response.success == true) {
        List<SjFriendListItemData> list =
            List<SjFriendListItemData>.from(state.friendList ?? []);
        list.removeWhere((element) => element.userId == event.followUserId);
        emit(state.copyWith(friendList: list));
        EasyLoading.showSuccess('Unfollow Successfully',
            duration: const Duration(seconds: 2));
      }
    } catch (e) {
      emit(state.copyWith(loading: false));
    }
  }

  FutureOr<void> _onAddBlock(
      SjHomeEventInsertRecord event, Emitter<SjHomeState> emit) async {
    EasyLoading.show(status: 'Loading...');
    SjResponseData response = await repository.insertRecord(
        event.broadcasterId, event.complainCategory, event.complainSub);
    if (response.success != null && response.success == true) {
      response = await repository.unFriend(event.broadcasterId ?? '');
      if (response.success != null && response.success == true) {
        List<SjFriendListItemData> list =
            List<SjFriendListItemData>.from(state.friendList ?? []);
        list.removeWhere((element) => element.userId == event.broadcasterId);
        emit(state.copyWith(friendList: list));
      }
      List<SjBroadCasterData>? wallList =
          await SjStorageUtils.getWallSearchList();
      if (wallList == null || wallList.isEmpty) {
        wallList = await repository.getWallSearch();
        wallList = await repository.getWallSearch();
        await SjStorageUtils.saveWallSearch(wallList);
      }
      List<SjWorksModel>? works = await SjStorageUtils.getWorksList();
      if (works == null || works.isEmpty) {
        works = SjUtils.mockWorksMatchCaster(wallList);
        SjStorageUtils.saveWorksList(works);
      }
      works ??= [];
      final list = await repository.blockList();
      List<SjWorksModel> result = List.from([]);
      bool match = false;
      for (var element in works) {
        match = false;
        for (var block in list) {
          if (element.userId == block.broadcasterId) {
            match = true;
            break;
          }
        }
        if (!match) {
          result.add(element);
        }
      }

      emit(state.copyWith(loading: false, worksList: result, blokList: list));
      EasyLoading.dismiss();
      EasyLoading.showSuccess('Block successfully',
          duration: const Duration(seconds: 2));
      event.callback?.call();
    }
  }

  FutureOr<void> _onLoadBlockList(
      SjHomeEventLoadedBlockList event, Emitter<SjHomeState> emit) async {
    try {
      final list = await repository.blockList();
      emit(state.copyWith(blokList: list));
    } catch (e) {
      emit(state.copyWith(loading: false));
    }
  }

  FutureOr<void> _onLoadFollowList(
      SjHomeEventLoadedFollowList event, Emitter<SjHomeState> emit) async {
    try {
      final list = await repository.friendList();
      emit(state.copyWith(friendList: list));
    } catch (e) {
      emit(state.copyWith(loading: false));
    }
  }

  FutureOr<void> _onAddReport(
      SjHomeEventInsertReport event, Emitter<SjHomeState> emit) async {
    SjResponseData response = await repository.insertRecord(
        event.broadcasterId, event.complainCategory, event.complainSub);
    if (response.success != null && response.success == true) {
      EasyLoading.showSuccess('Report successfully',
          duration: const Duration(seconds: 2));
      if (event.callback != null) {
        event.callback?.call();
      }
    }
  }
}
